package com.aipartner.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.util.Base64;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 豆包绘画API客户端 (doubao-seedream-4-0-250828)
 * 
 * @author AI Partner Team
 * @since 2024-01-20
 */
@Slf4j
@Service("doubaoPaintingClient")
public class DoubaoPaintingClient {
    
    @Value("${ai-partner.ai-models.doubao-painting.api-url:https://ark.cn-beijing.volces.com/api/v3/images/generations}")
    private String apiUrl;
    
    @Value("${ai-partner.ai-models.doubao-painting.api-key:${DOUBAO_PAINTING_API_KEY:dummy-local-key}}")
    private String apiKey;
    
    @Value("${ai-partner.ai-models.doubao-painting.model-name:doubao-seedream-4-0-250828}")
    private String modelName;
    
    @Value("${ai-partner.ai-models.doubao-painting.reference-image-field:image}")
    private String referenceImageField;
    
    @Value("${ai-partner.ai-models.doubao-painting.enabled:true}")
    private boolean enabled;
    
    @Value("${ai-partner.ai-models.doubao-painting.quality:hd}")
    private String quality;
    
    @Value("${ai-partner.ai-models.doubao-painting.remove-watermark:true}")
    private boolean removeWatermark;
    
    @Value("${ai-partner.ai-models.doubao-painting.enhance-quality:true}")
    private boolean enhanceQuality;
    
    @Value("${ai-partner.ai-models.doubao-painting.high-resolution:true}")
    private boolean highResolution;
    
    @Value("${ai-partner.ai-models.doubao-painting.output-format:png}")
    private String outputFormat;
    
    @Value("${ai-partner.ai-models.doubao-painting.sampling-steps:50}")
    private int samplingSteps;
    
    @Value("${ai-partner.ai-models.doubao-painting.cfg-scale:7.5}")
    private double cfgScale;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final RestTemplate restTemplate = new RestTemplate();
    
    /**
     * 提交图片生成任务
     */
    public JsonNode submitImageTask(String prompt, String size, String style) {
        return submitImageTask(prompt, size, style, null);
    }
    
    /**
     * 提交图片生成任务（支持参考图）
     */
    public JsonNode submitImageTask(String prompt, String size, String style, String referenceImagePath) {
        if (!enabled) {
            ObjectNode errorResponse = objectMapper.createObjectNode();
            errorResponse.put("code", 500);
            errorResponse.put("message", "豆包绘画服务未启用");
            return errorResponse;
        }
        
        log.info("使用豆包绘画API生成图片: model={}, prompt={}, size={}, style={}, referenceImage={}", 
            modelName, prompt, size, style, referenceImagePath != null ? "已提供" : "无");
        
        try {
            // 构造请求体（根据火山引擎官方文档格式）
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("model", modelName);
            requestBody.put("prompt", prompt);
            requestBody.put("size", convertSize(size)); // 转换尺寸格式
            requestBody.put("response_format", "url"); // 返回格式：url 或 b64_json
            requestBody.put("watermark", true); // 根据官方文档设置为true
            
            // 移除extra_params，直接使用官方文档标准参数
            // 根据官方文档，主要参数已经包含在基础请求体中
            
            // 如果有参考图，添加到请求中（根据火山引擎官方文档）
            if (referenceImagePath != null && !referenceImagePath.trim().isEmpty()) {
                log.info("处理参考图: {}", referenceImagePath);
                
                try {
                    if (referenceImagePath.startsWith("http://") || referenceImagePath.startsWith("https://")) {
                        if (isLocalOrPrivateAddress(referenceImagePath)) {
                            // localhost或局域网地址，转换为Base64
                            log.info("🔄 本地/局域网地址转换为Base64编码: {}", referenceImagePath);
                            String base64Image = convertLocalImageToBase64(referenceImagePath);
                            if (base64Image != null) {
                                requestBody.put("image", base64Image);
                                log.info("✅ 已添加参考图Base64到请求中，长度: {}KB", base64Image.length() / 1024);
                            } else {
                                log.error("❌ Base64转换失败，跳过参考图");
                            }
                        } else {
                            // 公网地址，直接使用URL
                            requestBody.put("image", referenceImagePath);
                            log.info("✅ 已添加参考图URL到请求中: {}", referenceImagePath);
                        }
                    } else {
                        // 本地文件路径，转换为Base64
                        log.info("🔄 本地文件转换为Base64编码");
                        String base64Image = convertLocalFileToBase64(referenceImagePath);
                        if (base64Image != null) {
                            requestBody.put("image", base64Image);
                            log.info("✅ 已添加参考图Base64到请求中，长度: {}KB", base64Image.length() / 1024);
                        } else {
                            log.error("❌ Base64转换失败，跳过参考图");
                        }
                    }
                    
                    // 如果添加了参考图，禁用连续生成
                    if (requestBody.containsKey("image")) {
                        requestBody.put("sequential_image_generation", "disabled");
                        log.info("请求体参数: model={}, prompt={}, size={}, 包含参考图=true", 
                            requestBody.get("model"), requestBody.get("prompt"), requestBody.get("size"));
                    }
                    
                } catch (Exception e) {
                    log.warn("处理参考图失败: {}, 继续进行纯文本生图", e.getMessage());
                }
            }
            
            log.info("豆包绘画参数: watermark={}, 使用官方文档标准参数格式", !removeWatermark);
            
            // 🚨 关键调试：检查requestBody中的参考图参数
            if (requestBody.containsKey("image")) {
                String imageValue = requestBody.get("image").toString();
                if (imageValue.startsWith("data:image/")) {
                    // Base64格式
                    int commaIndex = imageValue.indexOf(",");
                    String format = imageValue.substring(11, imageValue.indexOf(";"));
                    log.error("🚨🚨🚨 requestBody包含image参数(Base64格式):");
                    log.error("  - 格式: {}", format);
                    log.error("  - 完整前缀: {}", commaIndex > 0 ? imageValue.substring(0, commaIndex + 1) : "格式错误");
                    log.error("  - 数据长度: {} 字符", imageValue.length());
                    log.error("  - 数据预览: {}", imageValue.length() > 100 ? imageValue.substring(0, 100) + "..." : imageValue);
                } else if (imageValue.startsWith("http")) {
                    // URL格式
                    log.error("🚨🚨🚨 requestBody包含image参数(URL格式)，值: {}", imageValue);
                } else {
                    // 其他格式
                    log.error("🚨🚨🚨 requestBody包含image参数(未知格式):");
                    log.error("  - 长度: {} 字符", imageValue.length());
                    log.error("  - 开头: {}", imageValue.length() > 50 ? imageValue.substring(0, 50) + "..." : imageValue);
                }
            } else {
                log.info("🚨🚨🚨 requestBody不包含image参数 - 纯文本生图");
            }
            
            // 如果有风格参数，加入到prompt中
            if (style != null && !style.isEmpty()) {
                requestBody.put("prompt", prompt + ", style: " + style);
            }
            
            // 构建请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            // 检查API Key是否需要Base64解码
            String actualApiKey = apiKey;
            try {
                // 尝试Base64解码
                String decoded = new String(java.util.Base64.getDecoder().decode(apiKey));
                if (decoded.length() > 10) { // 合理的API Key长度
                    actualApiKey = decoded;
                    log.info("豆包API Key已解码");
                }
            } catch (Exception e) {
                log.info("豆包API Key无需解码，直接使用");
            }
            
            headers.setBearerAuth(actualApiKey);
            
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
            
            // 打印请求体（处理Base64显示）
            Map<String, Object> logRequestBody = new HashMap<>(requestBody);
            if (logRequestBody.containsKey("image") && logRequestBody.get("image") != null) {
                String imageValue = logRequestBody.get("image").toString();
                if (imageValue.startsWith("data:image/")) {
                    // Base64格式，只显示前缀和长度
                    int commaIndex = imageValue.indexOf(",");
                    if (commaIndex > 0) {
                        String prefix = imageValue.substring(0, commaIndex + 1);
                        logRequestBody.put("image", prefix + "[Base64数据，总长度: " + imageValue.length() + " 字符]");
                    }
                }
            }
            log.info("发送请求到豆包绘画API: {}", logRequestBody);
            
            // 发送请求
            ResponseEntity<String> response = restTemplate.postForEntity(apiUrl, request, String.class);
            
            JsonNode responseJson = objectMapper.readTree(response.getBody());
            log.info("豆包绘画API响应: {}", responseJson);
            
            return responseJson;
            
        } catch (Exception e) {
            log.error("调用豆包绘画API失败: {}", e.getMessage(), e);
            
            ObjectNode errorResponse = objectMapper.createObjectNode();
            errorResponse.put("code", 500);
            errorResponse.put("message", "API调用失败: " + e.getMessage());
            return errorResponse;
        }
    }
    
    /**
     * 查询任务状态 - 豆包绘画API是同步的，无需查询状态
     */
    public JsonNode queryTaskStatus(String taskId) {
        log.info("豆包绘画API是同步返回结果，无需查询状态: taskId={}", taskId);
        
        ObjectNode response = objectMapper.createObjectNode();
        response.put("code", 200);
        response.put("message", "success");
        response.put("task_id", taskId);
        response.put("status", "completed");
        
        return response;
    }
    
    /**
     * 下载网络图片并编码为Base64字符串
     * 优化：对于localhost地址，直接从本地文件系统读取，避免网络请求
     */
    private String downloadAndEncodeImage(String imageUrl) {
        try {
            // 对于localhost地址，尝试直接从本地文件系统读取
            if (imageUrl.contains("localhost") || imageUrl.contains("127.0.0.1")) {
                return downloadLocalImageAsBase64(imageUrl);
            }
            
            // 对于真正的网络地址，使用HTTP下载
            URL url = new URL(imageUrl);
            try (InputStream inputStream = url.openStream()) {
                byte[] imageBytes = inputStream.readAllBytes();
                String base64String = Base64.getEncoder().encodeToString(imageBytes);
                log.info("成功下载并编码网络图片: {} -> Base64 ({} bytes)", imageUrl, imageBytes.length);
                return base64String;
            }
        } catch (Exception e) {
            log.error("下载并编码网络图片失败: {} - {}", imageUrl, e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 从localhost URL直接读取本地文件并编码为Base64
     */
    private String downloadLocalImageAsBase64(String localhostUrl) {
        try {
            log.info("🔧 开始处理localhost URL: {}", localhostUrl);
            
            // 从localhost URL中提取文件路径
            // 例如: http://localhost:8080/uploads/reference-images/xxx.jpg
            // 提取: /uploads/reference-images/xxx.jpg
            String pathPart = localhostUrl.substring(localhostUrl.indexOf("/uploads/"));
            
            // 构造实际的文件路径
            String actualFilePath = "." + pathPart; // ./uploads/reference-images/xxx.jpg
            
            log.info("从localhost URL提取文件路径: {} -> {}", localhostUrl, actualFilePath);
            
            // 直接读取本地文件
            File imageFile = new File(actualFilePath);
            if (!imageFile.exists()) {
                log.error("❌ 本地文件不存在: {}", actualFilePath);
                return null;
            }
            
            log.info("📁 文件存在，大小: {} bytes", imageFile.length());
            
            // 🔄 尝试压缩图片，减小文件大小
            byte[] imageBytes = compressImage(imageFile);
            if (imageBytes == null) {
                // 压缩失败，使用原文件
                imageBytes = Files.readAllBytes(imageFile.toPath());
                log.info("图片压缩失败，使用原文件");
            }
            
            String base64String = Base64.getEncoder().encodeToString(imageBytes);
            
            // 🔍 严格的Base64验证和清理
            base64String = cleanBase64String(base64String);
            
            if (!isValidBase64(base64String)) {
                log.error("❌ Base64格式验证失败");
                return null;
            }
            
            log.info("✅ 成功编码本地图片: {} -> Base64 ({} bytes), 编码后长度: {} 字符", 
                actualFilePath, imageBytes.length, base64String.length());
            log.info("🔍 Base64格式验证通过，纯净字符串");
            
            // 🔍 额外的Base64调试信息
            analyzeBase64Content(base64String);
            
            return base64String;
            
        } catch (Exception e) {
            log.error("编码本地图片失败: {} - {}", localhostUrl, e.getMessage(), e);
            return null;
        }
    }

    /**
     * 将图片文件编码为Base64字符串
     */
    private String encodeImageToBase64(String imagePath) {
        try {
            File imageFile = new File(imagePath);
            if (!imageFile.exists()) {
                log.warn("参考图文件不存在: {}", imagePath);
                return null;
            }
            
            // 🔄 尝试压缩图片，减小文件大小
            byte[] imageBytes = compressImage(imageFile);
            if (imageBytes == null) {
                // 压缩失败，使用原文件
                imageBytes = Files.readAllBytes(imageFile.toPath());
                log.info("图片压缩失败，使用原文件");
            }
            
            String base64String = Base64.getEncoder().encodeToString(imageBytes);
            
            // 🔍 严格的Base64验证和清理
            base64String = cleanBase64String(base64String);
            
            if (!isValidBase64(base64String)) {
                log.error("❌ Base64格式验证失败");
                return null;
            }
            
            log.info("成功编码参考图: {} -> Base64 ({} bytes), 编码后长度: {} 字符", 
                imagePath, imageBytes.length, base64String.length());
            log.info("🔍 Base64格式验证通过，纯净字符串");
            
            // 🔍 额外的Base64调试信息
            analyzeBase64Content(base64String);
            
            return base64String;
            
        } catch (IOException e) {
            log.error("编码参考图失败: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 检查是否是本地或局域网地址
     */
    private boolean isLocalOrPrivateAddress(String url) {
        if (url == null) return false;
        
        return url.contains("localhost") || 
               url.contains("127.0.0.1") ||
               url.contains("192.168.") ||
               url.contains("10.") ||
               url.contains("172.16.") ||
               url.contains("172.17.") ||
               url.contains("172.18.") ||
               url.contains("172.19.") ||
               url.contains("172.20.") ||
               url.contains("172.21.") ||
               url.contains("172.22.") ||
               url.contains("172.23.") ||
               url.contains("172.24.") ||
               url.contains("172.25.") ||
               url.contains("172.26.") ||
               url.contains("172.27.") ||
               url.contains("172.28.") ||
               url.contains("172.29.") ||
               url.contains("172.30.") ||
               url.contains("172.31.");
    }
    
    /**
     * 从localhost URL转换图片为Base64
     */
    private String convertLocalImageToBase64(String localhostUrl) {
        try {
            log.info("🔧 处理localhost URL: {}", localhostUrl);
            
            // 从URL中提取文件路径：http://localhost:8080/uploads/reference-images/xxx.jpg -> ./uploads/reference-images/xxx.jpg
            String pathPart = localhostUrl.substring(localhostUrl.indexOf("/uploads/"));
            String filePath = "." + pathPart;
            
            return convertLocalFileToBase64(filePath);
            
        } catch (Exception e) {
            log.error("从localhost URL转换Base64失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 从本地文件路径转换图片为Base64（符合豆包API格式要求）
     */
    private String convertLocalFileToBase64(String filePath) {
        try {
            File imageFile = new File(filePath);
            if (!imageFile.exists()) {
                log.error("文件不存在: {}", filePath);
                return null;
            }
            
            log.info("📁 读取文件: {}, 大小: {} bytes", filePath, imageFile.length());
            
            // 获取文件扩展名，确定图片格式
            String fileName = imageFile.getName().toLowerCase();
            String imageFormat;
            if (fileName.endsWith(".png")) {
                imageFormat = "png";
            } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
                imageFormat = "jpeg";
            } else if (fileName.endsWith(".gif")) {
                imageFormat = "gif";
            } else if (fileName.endsWith(".webp")) {
                imageFormat = "webp";
            } else {
                // 默认当作jpeg处理
                imageFormat = "jpeg";
                log.warn("未知图片格式，默认使用jpeg: {}", fileName);
            }
            
            // 读取文件并编码为Base64
            byte[] imageBytes = Files.readAllBytes(imageFile.toPath());
            String base64 = Base64.getEncoder().encodeToString(imageBytes);
            
            // 按照豆包API要求的格式: data:image/<图片格式>;base64,<Base64编码>
            String formattedBase64 = String.format("data:image/%s;base64,%s", imageFormat, base64);
            
            log.info("✅ Base64编码完成: {} -> {} 字符 (格式: data:image/{};base64,...)", 
                imageFile.length(), formattedBase64.length(), imageFormat);
            log.info("🔍 Base64格式: data:image/{};base64,{}", imageFormat, 
                base64.length() > 50 ? base64.substring(0, 50) + "..." : base64);
            
            return formattedBase64;
            
        } catch (Exception e) {
            log.error("从本地文件转换Base64失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 压缩图片文件，减小文件大小
     */
    private byte[] compressImage(File imageFile) {
        try {
            BufferedImage originalImage = ImageIO.read(imageFile);
            if (originalImage == null) {
                log.error("无法读取图片文件: {}", imageFile.getName());
                return null;
            }
            
            int originalWidth = originalImage.getWidth();
            int originalHeight = originalImage.getHeight();
            
            // 如果图片太大，压缩到合适的尺寸（最大1024x1024）
            int maxDimension = 1024;
            int newWidth = originalWidth;
            int newHeight = originalHeight;
            
            if (originalWidth > maxDimension || originalHeight > maxDimension) {
                if (originalWidth > originalHeight) {
                    newWidth = maxDimension;
                    newHeight = (originalHeight * maxDimension) / originalWidth;
                } else {
                    newHeight = maxDimension;
                    newWidth = (originalWidth * maxDimension) / originalHeight;
                }
            }
            
            log.info("图片压缩: {}x{} -> {}x{}", originalWidth, originalHeight, newWidth, newHeight);
            
            // 创建压缩后的图片
            BufferedImage compressedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            compressedImage.createGraphics().drawImage(originalImage.getScaledInstance(newWidth, newHeight, BufferedImage.SCALE_SMOOTH), 0, 0, null);
            
            // 转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(compressedImage, "jpg", baos);
            byte[] compressedBytes = baos.toByteArray();
            
            log.info("图片压缩完成: {} bytes -> {} bytes (压缩比: {}%)", 
                imageFile.length(), compressedBytes.length, 
                (compressedBytes.length * 100) / imageFile.length());
            
            return compressedBytes;
            
        } catch (Exception e) {
            log.error("图片压缩失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 分析Base64内容，提供详细的调试信息
     */
    private void analyzeBase64Content(String base64) {
        if (base64 == null || base64.isEmpty()) {
            log.error("❌ Base64字符串为空，无法分析");
            return;
        }
        
        // 分析Base64字符串特征
        log.info("🔍 Base64详细分析:");
        log.info("  - 总长度: {} 字符", base64.length());
        log.info("  - 开头50字符: {}", base64.length() > 50 ? base64.substring(0, 50) : base64);
        log.info("  - 结尾50字符: {}", base64.length() > 50 ? base64.substring(base64.length() - 50) : base64);
        log.info("  - 包含换行符: {}", base64.contains("\n"));
        log.info("  - 包含回车符: {}", base64.contains("\r"));
        log.info("  - 包含空格: {}", base64.contains(" "));
        log.info("  - 是否以/9j/开头 (JPEG): {}", base64.startsWith("/9j/"));
        log.info("  - 是否以iVBORw0KGgo开头 (PNG): {}", base64.startsWith("iVBORw0KGgo"));
        
        // 计算padding
        long paddingCount = base64.chars().filter(c -> c == '=').count();
        log.info("  - Padding字符数: {}", paddingCount);
        
        // 预估解码后的文件大小
        long estimatedSize = (base64.length() * 3L) / 4L - paddingCount;
        log.info("  - 预估文件大小: {} bytes ({} KB)", estimatedSize, estimatedSize / 1024);
    }

    /**
     * 清理Base64字符串，移除可能的无效字符
     */
    private String cleanBase64String(String base64) {
        if (base64 == null) return null;
        
        // 移除所有换行符、空格、制表符等空白字符
        return base64.replaceAll("\\s+", "")
                     .replaceAll("\\r", "")
                     .replaceAll("\\n", "");
    }
    
    /**
     * 验证Base64字符串格式是否正确
     */
    private boolean isValidBase64(String base64) {
        try {
            if (base64 == null || base64.isEmpty()) {
                log.error("❌ Base64字符串为空");
                return false;
            }
            
            // 检查字符是否都是有效的Base64字符
            if (!base64.matches("^[A-Za-z0-9+/]*={0,2}$")) {
                log.error("❌ Base64包含无效字符，长度: {}, 开头: {}", 
                    base64.length(), 
                    base64.length() > 50 ? base64.substring(0, 50) : base64);
                return false;
            }
            
            // Base64长度必须是4的倍数（除了最后的padding）
            if (base64.length() % 4 != 0) {
                log.error("❌ Base64长度不是4的倍数: {}", base64.length());
                return false;
            }
            
            // 尝试解码验证
            byte[] decoded = Base64.getDecoder().decode(base64);
            if (decoded.length == 0) {
                log.error("❌ Base64解码后长度为0");
                return false;
            }
            
            log.info("✅ Base64格式验证通过: 长度={}, 解码后字节数={}", base64.length(), decoded.length);
            return true;
        } catch (Exception e) {
            log.error("❌ Base64验证失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 转换尺寸格式
     * 从 "1:1", "9:16", "16:9" 转换为高清4K尺寸
     */
    private String convertSize(String size) {
        if (size == null || size.isEmpty()) {
                return "2K"; // 默认2K
        }
        
        switch (size) {
            case "1:1":
                return "2048x2048"; // 正方形
            case "9:16":
                return "1024x1792"; // 竖屏
            case "16:9":
                return "1792x1024"; // 横屏
            case "3:4":
                return "1024x1360"; // 3:4竖屏
            case "4:3":
                return "1360x1024"; // 4:3横屏
            default:
                // 尝试解析宽高比
                try {
                    String[] parts = size.split(":");
                    if (parts.length == 2) {
                        int w = Integer.parseInt(parts[0]);
                        int h = Integer.parseInt(parts[1]);
                        
                        // 按比例计算4K尺寸，保持最大边不超过3840
                        if (w > h) {
                            int maxW = 3840;
                            int calcH = (int) ((double) maxW * h / w);
                            return maxW + "x" + calcH;
                        } else if (h > w) {
                            int maxH = 3840;
                            int calcW = (int) ((double) maxH * w / h);
                            return calcW + "x" + maxH;
                        } else {
                            return "2048x2048"; // 正方形
                        }
                    }
                } catch (Exception e) {
                    log.warn("无法解析尺寸格式: {}, 使用默认尺寸", size);
                }
                // 如果已经是具体尺寸格式，直接返回
                if (size.contains("x")) {
                    return size;
                }
                // 支持简化格式
                if (size.equalsIgnoreCase("2K")) {
                    return "2K";
                }
                if (size.equalsIgnoreCase("4K")) {
                    return "4K";
                }
                return "2048x2048";
        }
    }
}
